package com.test.mytest.javacv.samples;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.bytedeco.javacpp.opencv_core.CV_32SC1;
import static org.bytedeco.javacpp.opencv_core.CV_8UC1;
import static org.bytedeco.javacpp.opencv_face.createFisherFaceRecognizer;
// import static org.bytedeco.javacpp.opencv_face.createEigenFaceRecognizer;
// import static org.bytedeco.javacpp.opencv_face.createLBPHFaceRecognizer;
import static org.bytedeco.javacpp.opencv_imgcodecs.imread;
import static org.bytedeco.javacpp.opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE;

import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacpp.opencv_face.FaceRecognizer;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.MatVector;

/**
 * I couldn't find any tutorial on how to perform face recognition using OpenCV and Java,
 * so I decided to share a viable solution here. The solution is very inefficient in its
 * current form as the training model is built at each run, however it shows what's needed
 * to make it work.
 *
 * The class below takes two arguments: The path to the directory containing the training
 * faces and the path to the image you want to classify. Not that all images has to be of
 * the same size and that the faces already has to be cropped out of their original images
 * (Take a look here http://fivedots.coe.psu.ac.th/~ad/jg/nui07/index.html if you haven't
 * done the face detection yet).
 *
 * For the simplicity of this post, the class also requires that the training images have
 * filename format: <label>-rest_of_filename.png. For example:
 *
 * 1-jon_doe_1.png
 * 1-jon_doe_2.png
 * 2-jane_doe_1.png
 * 2-jane_doe_2.png
 * ...and so on.
 *
 * Source: http://pcbje.com/2012/12/doing-face-recognition-with-javacv/
 *
 * @author Petter Christian Bjelland
 */
public class OpenCVFaceRecognizer {
    private FaceRecognizer faceRecognizer;
	private String name;
	private double confidence;
    private String names[];

	public static void main(String[] args) {
    	//头像训练数据
        String registeredFaceDir = System.getProperty("user.dir")+"\\image\\javacv\\face\\";
        String testImagePath = registeredFaceDir+"hjx3.jpg";//要识别的头像
		String trainingDir = registeredFaceDir;
		Mat testImage = imread(testImagePath, CV_LOAD_IMAGE_GRAYSCALE);

        File root = new File(trainingDir);

        FilenameFilter imgFilter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                name = name.toLowerCase();
                return name.endsWith(".jpg") || name.endsWith(".pgm") || name.endsWith(".png");
            }
        };
        System.out.println(trainingDir+"===="+testImagePath);
        File[] imageFiles = root.listFiles(imgFilter);

//        int length = imageFiles.length;
//		MatVector images = new MatVector(length);
//        Mat labels = new Mat(length, 1, CV_32SC1);
//        IntBuffer labelsBuf = labels.createBuffer();
//
//        int counter = 0;
//
//        for (File image : imageFiles) {
//            Mat img = imread(image.getAbsolutePath(), CV_LOAD_IMAGE_GRAYSCALE);
//
//            String name = image.getName();
//            System.out.println(name+"=="+name.lastIndexOf("."));
//            name=name.substring(0, name.lastIndexOf("."));
//			int label = Integer.parseInt(name.substring(name.length()-1));
//			System.out.println("label==="+label);
//            images.put(counter, img);
//            labelsBuf.put(counter, label);
//
//            counter++;
//        }
//
//        FaceRecognizer faceRecognizer = createFisherFaceRecognizer();
//        // FaceRecognizer faceRecognizer = createEigenFaceRecognizer();
//        // FaceRecognizer faceRecognizer = createLBPHFaceRecognizer()
//
//        faceRecognizer.train(images, labels);
//
//        IntPointer label = new IntPointer(1);
//        DoublePointer confidence = new DoublePointer(1);
//        faceRecognizer.predict(testImage, label, confidence);
//        int predictedLabel = label.get(0);
//
//        System.out.println("Predicted label: " + predictedLabel+"===confidence:"+confidence.get());
        
        OpenCVFaceRecognizer r=new OpenCVFaceRecognizer();
        r.init(Arrays.asList(imageFiles));
        r.predict(testImage);
    }
    
    public void init(List<File> list){
    	int length = list.size();
    	MatVector images = new MatVector(length);
    	names=new String[length];
        Mat labels = new Mat(length, 1, CV_32SC1);
        IntBuffer labelsBuf = labels.createBuffer();

        int counter = 0;

        for (File image : list) {
            Mat img = imread(image.getAbsolutePath(), CV_LOAD_IMAGE_GRAYSCALE);

            String name = image.getName();
            System.out.println(name+"=="+name.lastIndexOf("."));
            name=name.substring(0, name.lastIndexOf("."));
			int label = Integer.parseInt(name.substring(name.length()-1));
			System.out.println("label==="+label);
			names[counter]=name;
            images.put(counter, img);

            labelsBuf.put(counter, counter);

            counter++;
        }
        faceRecognizer = createFisherFaceRecognizer();
        // faceRecognizer = createEigenFaceRecognizer();
        // faceRecognizer = createLBPHFaceRecognizer();

        faceRecognizer.train(images, labels);
    }
    
    public  void predict(Mat mat){
    	IntPointer label = new IntPointer(1);
        DoublePointer confidence = new DoublePointer(1);
        faceRecognizer.predict(mat, label, confidence);
        int predictedLabel = label.get(0);
        name=names[predictedLabel];
        this.confidence=confidence.get();
        System.out.println("name:"+name+"===Predicted label: " + predictedLabel+"===confidence:"+confidence.get());
    }

	public String getName() {
		return name;
	}

	public double getConfidence() {
		return confidence;
	}
}